using System;
using System.Collections.Generic;
using Unity.VisualScripting;

public interface ISingleton : IDisposable
{
    public void RegisterSingleton();
}

public interface ISingletonUpdata
{
    public void OnUpdate();
}

public interface ISingeletonBaseDestroy
{
    public void Destroy();
}

/// <summary>
/// 泛型单例基类
/// </summary>
/// <typeparam name="T">单例类型</typeparam>
public class Singleton<T> : ISingeletonBaseDestroy where T : class, ISingleton, new()
{
    private static T _instance;
    private static readonly object _lock = new object();

    /// <summary>
    /// 获取单例实例
    /// </summary>
    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new T();
                        _instance.RegisterSingleton();
                    }
                }
            }
            return _instance;
        }
    }

    public void RegisterSingleton()
    {
        SingletonManager.RegisterSingleton<T>(this);
    }

    /// <summary>
    /// 销毁单例实例
    /// </summary>
    public static void DestroyInstance()
    {
        if (_instance != null)
        {
            _instance.Dispose();
            SingletonManager.UnregisterSingleton<T>();
            _instance = null;
        }
    }

    public void Destroy()
    {
        if (_instance != null)
        {
            _instance.Dispose();
            SingletonManager.UnregisterSingleton<T>();
            _instance = null;
        }
    }

    /// <summary>
    /// 检查单例是否存在
    /// </summary>
    public static bool HasInstance => _instance != null;
}

public static class SingletonManager
{
    private static Dictionary<Type, object> _singletons = new Dictionary<Type, object>();

    public static T GetSingleton<T>() where T : class, ISingleton, new()
    {
        return Singleton<T>.Instance;
    }

    public static void DestroySingleton<T>() where T : class, ISingleton, new()
    {
        Singleton<T>.DestroyInstance();
    }

    public static void DestroyAllSingletons()
    {
        var singletons = new List<object>(_singletons.Values);
        var count = singletons.Count;
        for (int i = 0; i < count; i++)
        {
            var singleton = singletons[i];
            if (singleton is ISingeletonBaseDestroy disposable)
            {
                disposable.Destroy();
            }
        }
        _singletons.Clear();
    }

    public static bool HasSingleton<T>() where T : class, ISingleton, new()
    {
        Type type = typeof(T);
        return _singletons.ContainsKey(type);
    }

    public static void RegisterSingleton<T>(object singleton) where T : class, ISingleton, new()
    {
        if (singleton == null)
            return;
        Type type = typeof(T);
        if (!_singletons.ContainsKey(type))
        {
            _singletons[type] = singleton;
        }
    }

    public static void UnregisterSingleton<T>() where T : class, ISingleton, new()
    {
        Type type = typeof(T);
        if (_singletons.ContainsKey(type))
        {
            _singletons.Remove(type);
        }
    }

    public static void UpdateAllSingletons()
    {
        foreach (var singleton in _singletons.Values)
        {
            var updatable = singleton as ISingletonUpdata;
            if (updatable != null)
            {
                updatable.OnUpdate();
            }
        }
    }
}
